package com.app.aspect;

import com.alibaba.fastjson.JSON;
import com.app.model.aspect.OperatorLog;
import com.app.service.AspectService;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * Created by Lichaojie on 2017/8/10. It's a beautiful day.
 */

/**
 * @Component 可替换为 @Named
 * @Autowired 可替换为 @Inject
 */
@Aspect
@Component
public class ControllerAspect {
    private final Logger logger = Logger.getLogger(ControllerAspect.class);

    private ThreadLocal<OperatorLog> tlocal = new ThreadLocal<>();

    @Autowired
    private AspectService aspectService;

    @Pointcut("execution(* com.app.controller..*.*(..)) " +
            "&& @annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public void controllerMethodPointcut(){}

    @Before("controllerMethodPointcut()")
    public void doBefore(JoinPoint joinPoint){
        try {

            long beginTime = System.currentTimeMillis();
            //long time = System.nanoTime();

            // 接收到请求，记录请求内容
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            String beanName = joinPoint.getSignature().getDeclaringTypeName();
            String methodName = joinPoint.getSignature().getName();
            String uri = request.getRequestURI();
            String remoteAddr = getIpAddr(request);
            String sessionId = request.getSession().getId();
            String user = (String) request.getSession().getAttribute("user");
            String method = request.getMethod();
            String params;
            if ("POST".equals(method)) {
                Object[] paramsArray = joinPoint.getArgs();
                params = argsArrayToString(paramsArray);
            } else {
                Map<?, ?> paramsMap = (Map<?, ?>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
                params = paramsMap.toString();
            }

            logger.debug("uri=" + uri + "; beanName=" + beanName + "; remoteAddr=" + remoteAddr + "; user=" + user
                    + "; methodName=" + methodName + "; params=" + params);

            OperatorLog optLog = new OperatorLog();
            optLog.setBeanName(beanName);
            optLog.setCurUser(user);
            optLog.setMethodName(methodName);
            optLog.setParams(params != null ? params : "");
            optLog.setRemoteAddr(remoteAddr);
            optLog.setSessionId(sessionId);
            optLog.setUri(uri);
            optLog.setRequestTime(beginTime);
            tlocal.set(optLog);

        } catch (Exception e) {
            logger.error("***操作请求日志记录失败doBefore()***", e);
        }
    }


    @AfterReturning(returning = "result", pointcut = "controllerMethodPointcut()")
    public void doAfterReturning(Object result) {
        try {
            // 处理完请求，返回内容
            OperatorLog optLog = tlocal.get();
            optLog.setResult(result==null?"":result.toString());
            long beginTime = optLog.getRequestTime();
            long duration = (System.currentTimeMillis() - beginTime);
            optLog.setDuration(duration);

//            logger.info("uri=" + optLog.getUri() + "," +
//                    "requestTime=" + optLog.getRequestTime() + "," +
//                    "duration=" + optLog.getDuration());

            aspectService.saveLog(optLog);
        } catch (Exception e) {
            logger.error("***操作请求日志记录失败doAfterReturning()***", e);
        }
    }



    /**
     * 获取登录用户远程主机ip地址
     *
     * @param request http请求
     * @return 返回登录用户的远程主机IP地址
     */
    private String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 请求参数拼装
     *
     * @param paramsArray 请求参数
     * @return 将请求参数拼装成一定格式的字符串
     */
    private String argsArrayToString(Object[] paramsArray) {
        String params = "";
        if (paramsArray != null && paramsArray.length > 0) {
            for (Object object : paramsArray){
                Object jsonObj = JSON.toJSON(object);
                params += (jsonObj.toString() + " ");
            }
        }
        return params.trim();
    }
}
